package cn.tqfeiyang.smartadmin.commons.mybatis;

import cn.hutool.cache.Cache;
import cn.tqfeiyang.smartadmin.commons.toolbox.CacheUtils;
import cn.tqfeiyang.smartadmin.commons.toolbox.GenericTypeUtils;
import jakarta.annotation.Resource;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 实体广播
 *
 * @author tqfeiyang
 * @since 2024/9/26 10:11
 */
@Component
@Slf4j
public class EntityBroadcast {

    @Resource
    private ApplicationContext applicationContext;

    private Cache<Class<?>, EntityData> cacheData = CacheUtils.newCache();


    private Cache<Class<?>, List<IEntityListener>> listenerBeansCache = CacheUtils.newCache();

    /**
     * 添加前处理
     *
     * @param entity 实体对象
     */
    public <T> void beforeCreate(T entity) {
        getEntityListeners(entity.getClass()).forEach(listener -> listener.beforeCreate(entity));
    }

    /**
     * 添加后处理
     *
     * @param entity 实体对象
     */
    public <T> void afterCreate(T entity) {
        getEntityListeners(entity.getClass()).forEach(listener -> listener.afterCreate(entity));
    }

    /**
     * 修改前处理
     *
     * @param entity 实体对象
     */
    public <T> void beforeUpdate(T entity) {
        getEntityListeners(entity.getClass()).forEach(listener -> listener.beforeUpdate(entity));
    }

    /**
     * 修改后处理
     *
     * @param entity 实体对象
     */
    public <T> void afterUpdate(T entity) {
        getEntityListeners(entity.getClass()).forEach(listener -> listener.afterUpdate(entity));
    }

//    /**
//     * 删除前处理
//     *
//     * @param entity 实体对象
//     */
//    public <T> void beforeDelete(T entity) {
//        getEntityListeners(entity.getClass()).forEach(listener -> listener.beforeDelete(entity));
//    }

//    /**
//     * 删除后处理
//     *
//     * @param entity 实体对象
//     */
//    public <T> void afterDelete(T entity) {
//        getEntityListeners(entity.getClass()).forEach(listener -> listener.afterDelete(entity));
//    }

    /**
     * 获取支持实体类的所有bean
     *
     * @param entityClass
     * @return bean列表
     */
    private List<IEntityListener> getEntityListeners(Class<?> entityClass) {
        return listenerBeansCache.get(entityClass, () -> {
            Map<String, IEntityListener> map = applicationContext.getBeansOfType(IEntityListener.class);
            return map.values().stream().filter(bean -> {
                List<Class<?>> genericTypes = GenericTypeUtils.resolveTypeArguments(bean.getClass());
                return genericTypes.size() > 0 && entityClass.isAssignableFrom(genericTypes.get(0));
            }).toList();
        });
    }

    /**
     * 验证实体数据
     *
     * @param entity 实体对象
     * @param creating 添加时为true，修改是为false
     */
    public <T> void validate(T entity, boolean creating) {
        Assert.notNull(entity, "entity不能为空");
        Class<?> clazz = entity.getClass();
        getEntityData(clazz).getValidators().stream()
                .forEach(bean -> bean.validate(entity, creating));
    }

    /**
     * 删除实体前检查
     *
     * @param entity 实体对象
     */
    public <T> void beforeDelete(T entity) {
        Assert.notNull(entity, "entity不能为空");
        Class<?> clazz = entity.getClass();
        getEntityData(clazz).getValidators().stream()
                .forEach(bean -> bean.beforeDelete(entity));
    }

    /**
     * 删除实体后处理
     *
     * @param entity 实体对象
     */
    public <T> void afterDelete(T entity) {
        Assert.notNull(entity, "entity不能为空");
        Class<?> clazz = entity.getClass();
        getEntityData(clazz).getValidators().stream()
                .forEach(bean -> bean.afterDelete(entity));
    }

    /**
     * 清理缓存
     *
     * @param clazz 实例类型
     */
    public void clearCache(Class<?> clazz) {
        Assert.notNull(clazz, "clazz不能为空");
        getEntityData(clazz).getCaches().stream()
                .forEach(bean -> bean.clearCache());
    }

    /**
     * 获取实体接口数据
     *
     * @param clazz 实例类型
     * @return 接口数据
     */
    private EntityData getEntityData(Class<?> clazz) {
        return cacheData.get(clazz, () -> new EntityData(clazz));
    }

    /**
     * 实体相关接口数据
     */
    class EntityData {

        @Getter
//        List<IEntityValidator> validators = new ArrayList<>();
//
//        @Getter
//        List<IEntityCache> caches = new ArrayList<>();

        private List<IEntityHandler> beans = new ArrayList<>();

        EntityData(Class<?> entityClass) {
            applicationContext.getBeansOfType(IEntityHandler.class).values().stream().forEach(bean -> {
                List<Class<?>> genericTypes = GenericTypeUtils.resolveTypeArguments(bean.getClass());
                if (genericTypes.size() > 0 && entityClass.isAssignableFrom(genericTypes.get(0))) {
                    beans.add(bean);
                }
            });


//            applicationContext.getBeansOfType(IEntityValidator.class).values().stream().forEach(bean -> {
//                List<Class<?>> genericTypes = GenericTypeUtils.resolveTypeArguments(bean.getClass());
//                if (genericTypes.size() > 0 && entityClass.isAssignableFrom(genericTypes.get(0))) {
//                    validators.add(bean);
//                }
//            });
//
//            applicationContext.getBeansOfType(IEntityCache.class).values().stream().forEach(bean -> {
//                List<Class<?>> genericTypes = GenericTypeUtils.resolveTypeArguments(bean.getClass());
//                if (genericTypes.size() > 0 && entityClass.isAssignableFrom(genericTypes.get(0))) {
//                    caches.add(bean);
//                }
//            });
        }

        private List<IEntityValidator> getValidators() {
            List<IEntityValidator> validators = new ArrayList<>();
            beans.stream().forEach(bean -> {
                if (bean instanceof IEntityValidator<?>) {
                    validators.add((IEntityValidator<?>) bean);
                }
            });
            return validators;
        }

        private List<IEntityCache> getCaches() {
            List<IEntityCache> caches = new ArrayList<>();
            beans.stream().forEach(bean -> {
                if (bean instanceof IEntityCache<?>) {
                    caches.add((IEntityCache<?>) bean);
                }
            });
            return caches;
        }
    }
}
